package main

import (
	"bytes"
	"container/list"
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

type IdCard struct {
	CardNumber int
	Id         int
}

type Student struct {
	UserName string `json:"user_name,omitempty"`
	Password string `json:"password,omitempty"`
	Card     *IdCard
	IsOk     bool
}

func (this Student) Test(a, b int) int {
	fmt.Println(a, ":", b)
	return a + b
}

func makeLink(v interface{}) map[string]string {
	typ := reflect.TypeOf(v)
	kv := make(map[string]string)
	for i := 0; i < typ.NumField(); i++ {
		field := typ.Field(i)
		name := field.Name
		tag := field.Tag.Get("json")
		if len(tag) > 0 {
			split := strings.Split(tag, ",")
			name = split[0]
		}

		kv[field.Name] = name
	}

	return kv
}

func makeLink2(v interface{}) map[string]string {
	typ := reflect.TypeOf(v)
	kv := make(map[string]string)
	for i := 0; i < typ.NumField(); i++ {
		field := typ.Field(i)
		name := field.Name
		tag := field.Tag.Get("json")
		if len(tag) > 0 {
			split := strings.Split(tag, ",")
			name = split[0]
		}

		kv[name] = field.Name
	}

	return kv
}

func splitJson(jsonStr string) []string {
	stack := list.New()
	rect := make([]string, 0)
	begId := 0
	for i, c := range jsonStr {
		if c == rune('{') || c == rune('[') {
			stack.PushBack(struct{}{})
		} else if c == rune('}') || c == rune(']') {
			ele := stack.Back()
			if ele != nil {
				stack.Remove(ele)
			}
		} else if c == rune(',') {
			if stack.Len() == 0 {
				rect = append(rect, jsonStr[begId:i])
				begId = i + 1
			}
		}
	}
	return rect
}

func GetErrorOfNotPtr() error {
	return errors.New("the interface is not ptr")
}

func unMarsh(data []byte, v interface{}) error {
	var err error = nil
	s := string(data)
	s = strings.TrimLeft(s, " ")
	s = strings.TrimRight(s, " ")

	vf := reflect.ValueOf(v)
	typ := reflect.TypeOf(v)
	if vf.Kind() != reflect.Ptr {
		return GetErrorOfNotPtr()
	}
	vf = vf.Elem()
	typ = typ.Elem()

	switch vf.Kind() {
	case reflect.String:
		vf.SetString(s[1 : len(s)-1])
	case reflect.Bool:
		parseBool, e := strconv.ParseBool(s)
		err = e
		vf.SetBool(parseBool)
	case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		n, e := strconv.ParseInt(s, 10, 64)
		vf.SetInt(n)
		err = e
	case reflect.Slice:
		if s[0] == '[' && s[len(s)-1] == ']' {
			arr := splitJson(s[1 : len(s)-1])
			slice := reflect.MakeSlice(typ, len(arr), len(arr))
			vf.Set(slice)
			for i := 0; i < len(arr); i++ {
				eleValue := slice.Index(i)
				eleType := eleValue.Type()
				if eleType.Kind() != reflect.Ptr {
					eleValue = eleValue.Addr()
					unMarsh([]byte(arr[i]), eleValue.Interface())
				} else {
					newValue := reflect.New(eleType.Elem())
					unMarsh([]byte(arr[i]), newValue.Interface())
					eleValue.Set(newValue)
				}

			}
		}
	case reflect.Struct:
		if s[0] == '{' && s[len(s)-1] == '}' {
			arr := splitJson(s[1 : len(s)-1])
			kv := makeLink2(vf.Interface())
			for _, v := range arr {
				split := strings.SplitN(v, ":", 2)
				tag := split[0][1 : len(split[0])-1]

				s2, ok := kv[tag]
				if ok {
					field := vf.FieldByName(s2)
					if field.Kind() != reflect.Ptr {
						field = field.Addr()
						e := unMarsh([]byte(split[1]), field.Interface())
						if e != nil {
							err = e
							break
						}
					} else {
						newValue := reflect.New(field.Type().Elem())
						unMarsh([]byte(split[1]), newValue.Interface())
						vf.FieldByName(s2).Set(newValue)
					}

				}
			}
		}
	default:
		err = errors.New("暂不支持此类型")
	}

	return err
}

func Marsh(v interface{}) ([]byte, error) {
	vf := reflect.ValueOf(v)
	typ := vf.Type()

	if vf.Kind() == reflect.Ptr {
		vf = vf.Elem()
		typ = typ.Elem()
	}
	buf := bytes.Buffer{}
	var err error = nil
	switch typ.Kind() {
	case reflect.String:
		data := fmt.Sprintf(`"%s"`, vf.Interface())
		buf.Write([]byte(data))
	case reflect.Bool:
		data := fmt.Sprintf(`%t`, vf.Interface())
		buf.Write([]byte(data))
	case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		data := fmt.Sprintf("%v", vf.Interface())
		buf.Write([]byte(data))
	case reflect.Slice:
		if vf.IsNil() {
			buf.Write([]byte("null"))
			break
		}
		buf.WriteByte('[')
		if vf.Len() > 0 {
			for i := 0; i < vf.Len(); i++ {
				eleValue := vf.Index(i)

				if eleValue.Kind() != reflect.Ptr {
					data, e := Marsh(eleValue.Interface())
					if e != nil {
						err = e
						break
					}
					buf.Write(data)
					buf.WriteByte(',')
				} else {
					eleValue = eleValue.Elem()
					data, e := Marsh(eleValue.Interface())
					if e != nil {
						err = e
						break
					}
					buf.Write(data)
					buf.WriteByte(',')
				}

			}
			buf.Truncate(buf.Len() - 1)
		}
		buf.WriteByte(']')
	case reflect.Struct:
		buf.WriteByte('{')
		link := makeLink(vf.Interface())
		for i := 0; i < vf.NumField(); i++ {
			eName := typ.Field(i).Name
			name := link[eName]
			buf.WriteByte('"')
			buf.Write([]byte(name))
			buf.WriteByte('"')
			buf.WriteByte(':')

			eleValue := vf.Field(i)

			if eleValue.Kind() != reflect.Ptr {
				marsh, e := Marsh(eleValue.Interface())
				if err != nil {
					err = e
					break
				}
				buf.Write(marsh)
				buf.WriteByte(',')
			} else {
				if eleValue.IsNil() {
					buf.Write([]byte("null"))
					buf.WriteByte(',')
					continue
				}
				marsh, e := Marsh(eleValue.Elem().Interface())
				if err != nil {
					err = e
					break
				}
				buf.Write(marsh)
				buf.WriteByte(',')
			}

		}
		buf.Truncate(buf.Len() - 1)
		buf.WriteByte('}')
	case reflect.Interface:

	default:
		err = errors.New("暂不支持此类型")
	}
	return buf.Bytes(), err
}

func main() {
	//m := map[string]string{}
	//m["11"] = "11"
	//m["12"] = "12"
	//m["13"] = "13"
	//m["14"] = "14"
	//marshal, _ := json.Marshal(m)
	//fmt.Println(string(marshal))

	stu := make([]*Student, 0)
	stu2 := make([]*Student, 0)
	for i := 0; i < 3; i++ {
		s := &Student{}
		s.UserName = fmt.Sprintf("stu%d", i)
		s.Password = fmt.Sprintf("pass%d", i)
		stu = append(stu, s)
	}
	//student := Student{}
	//stu := &Student{}
	//student.UserName = "罗辉"
	//student.Password = "luohui123"
	//student.Card = new(IdCard)
	//student.Card.CardNumber = 100
	//student.Card.Id = 0
	marsh, err := Marsh(stu)
	fmt.Println(string(marsh))
	if err != nil {
		fmt.Println(err)
		return
	}

	err = unMarsh(marsh, &stu2)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(stu)
	//if err != nil {
	//	fmt.Println(err)
	//	return
	//}
	//stu := Student{}
	//err = json.Unmarshal(marsh, &stu)
	//if err != nil {
	//	fmt.Println(err)
	//	return
	//}
	//fmt.Println(string(marsh))
	//jsonStr, err := json.Marshal(stu)
	//if err != nil {
	//	fmt.Println(err)
	//	return
	//}
	//
	//is := splitJson(string(jsonStr[1:len(jsonStr)-1]), stu)
	//for i, s := range is {
	//	fmt.Println(i, ":", s)
	//}

	//data, err := json.Marshal(student)
	//if err != nil {
	//	fmt.Println(err)
	//}
	//link := makeLink(Student{})
	//for k, v := range link {
	//	fmt.Println(k, ":", v)
	//}
	//splitJson(string(data), student)
	//strings := splitJson(string(data[1:len(data)-1]), student)
	//for i, k := range strings {
	//	fmt.Println(i, ":", k)
	//}
	//fmt.Println(string(data))

	//trim := strings.Trim(" abc ", " ")
	//fmt.Println(trim)
}
